#include <WiFi.h>
#include <string.h>
#include <EEPROM.h>
#include <Ticker.h>
#include <WiFiUdp.h>
#include <Arduino.h>
#include <AceButton.h>
#include <WakeOnLan.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

#include "../include/main.h"
#include "../include/PubSubClient.h"  

using namespace ace_button;
WiFiClient espClient;
HTTPClient http_bemfa_HTTPClient;
WiFiClient client_bemfa_WiFiClient;
AceButton  ledButton(buttonPin);
PubSubClient client(espClient);

WiFiUDP UDP;
WakeOnLan WOL(UDP);

void handleEvent(AceButton* button, uint8_t eventType,uint8_t) {
  String Msgstring;
  String topicString;
  switch (eventType) {
    //当短按时
    case AceButton::kEventReleased:
      Serial.println(F("Button: Pressed"));

      ledState = !ledState;             //改变led状态
      digitalWrite(LED_Pin, ledState);  //写入状态

      if (ledState == true) {
        Serial.println("low press off");
        Msgstring = "off";
      } else {
        Serial.println("low press on");
        Msgstring = "on";
      }
      topicString = TOPIC + "/up";
      client.publish(topicString.c_str(), Msgstring.c_str());  //推送消息

      break;
      //当长按时
    case AceButton::kEventLongPressed:
      Serial.println(F("Button: Long Pressed"));

      Serial.println("Restore Factory....... ");
      config.magic = 0x00;
      config.reboot = 0;
      strcpy(config.stassid, "");
      strcpy(config.stapsw, "");
      strcpy(config.cuid, "");
      strcpy(config.ctopic, "");
      strcpy(config.MACAddress, "");
      saveConfig();

      doSmartconfig();
      int num = 0;
      while (WiFi.status() != WL_CONNECTED && num < 120) {  //检查是否连接成功
        delay(500);
        num = num + 1;
        Serial.print(".");
      }
      getUid(topicMac, true);
      break;
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String Mqtt_Buff = "";
  for (int i = 0; i < length; i++) {
    Mqtt_Buff += (char)payload[i];
  }
  Serial.print(Mqtt_Buff);
  Serial.println();
  
  // Switch on the LED if an 1 was received as first character
  if (Mqtt_Buff == "on") {
    turnOnLed();            
  } 
  else if (Mqtt_Buff == "off") {
    turnOffLed();                   
  }
  else {
    int index = Mqtt_Buff.indexOf("MAC=");
    if (index != -1) {
      String mac =  Mqtt_Buff.substring(index + 4);
      mac.toCharArray(buf,mac.length()+1);
      memcpy(config.MACAddress, buf, sizeof(buf));
      Serial.printf(buf);
      saveConfig();
    }
  }
  Mqtt_Buff = "";
}

/**
* 重新连接
*/
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(UID.c_str())) {
      Serial.println("connected");

      client.subscribe(TOPIC.c_str());  //订阅
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
/**
* 按键中断，仅在配网失败时使用
*/
static unsigned long buttonLastMillis = 0;  //时间戳，用于计算防抖
void IRAM_ATTR checkSwitch() {
  unsigned long newMillis = millis();  //获取当前时间戳

  if (newMillis - buttonLastMillis > 30) {  //检测短按，是否大于30ms
    Serial.println("low press !!!!!!!!");
    ledState = !ledState;             //改变led状态
    digitalWrite(LED_Pin, ledState);  //写入状态
  }
  buttonLastMillis = newMillis;  //重新计算防抖动
}

void getUid(String mac, bool reConfig) {
  if (strcmp(config.cuid, "") == 0 || reConfig) {

    http_bemfa_HTTPClient.begin(client_bemfa_WiFiClient, "http://api.bemfa.com/api/device/v1/airkiss/?topic=" + mac + "&version=" + verSion + "&ad=" + adminID);
    httpCode = http_bemfa_HTTPClient.GET();
    if (httpCode > 0) {
      String payload = http_bemfa_HTTPClient.getString();
      //json数据解析
      StaticJsonDocument<200> doc;
      DeserializationError error = deserializeJson(doc, payload);
      if (error) {
        Serial.print(F("deserializeJson() failed: "));
        Serial.println(error.c_str());
      }
      String code = doc["code"];
      if (code == "5723200") {
        String docUID = doc["uid"];
        strcpy(config.cuid, docUID.c_str());
        strcpy(config.ctopic, mac.c_str());
        saveConfig();
      } else {
        Serial.println(" config ERROR.........");
      }

      http_bemfa_HTTPClient.end();
    }
  }
  if (strcmp(config.ctopic, "") == 0) {
    TOPIC = mac;
  } else {
    TOPIC = config.ctopic;
  }
  UID = config.cuid;
}

/**
* 存储配网信息
*/
void saveConfig() {
  uint8_t mac[6];
  WiFi.macAddress(mac);
  config.reboot = 0;
  EEPROM.begin(256);
  uint8_t* p = (uint8_t*)(&config);
  for (int i = 0; i < sizeof(config); i++) {
    EEPROM.write(i, *(p + i));
  }
  EEPROM.commit();
}
Ticker delayTimer;
void delayRestart(float t) {
  delayTimer.attach(t, []() {
    ESP.restart();
  });
}


/**
* airkiss配网
*/
void doSmartconfig() {
  Serial.print(" Smartconfig begin,Waiting for WeChat Config.....");
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.stopSmartConfig();
  WiFi.beginSmartConfig();
  int cnt = 0;

  while (!WiFi.smartConfigDone()) {
    digitalWrite(LedBlink, HIGH);  //指示灯引脚
    delay(150);
    digitalWrite(LedBlink, LOW);  //指示灯引脚
    delay(150);
    if (WiFi.smartConfigDone()) {
      strcpy(config.stassid, WiFi.SSID().c_str());
      strcpy(config.stapsw, WiFi.psk().c_str());
      config.magic = 0xAA;
      saveConfig();
    }
    cnt++;
    if (cnt >= 600) {
      delayRestart(0);
    }
  }
  digitalWrite(LedBlink, LOW);  //指示灯引脚
  Serial.println("Smartconfig ok");
}

/**
* 初始化wifi信息，并连接路由器网络
*/
void initWiFi() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.disconnect();                          //断开连接
    WiFi.mode(WIFI_STA);                        //STA模式
    WiFi.begin(config.stassid, config.stapsw);  //连接路由器
  }
  int num = 0;
  while (WiFi.status() != WL_CONNECTED && num < 120) {  //检查是否连接成功
    delay(500);
    num = num + 1;
    Serial.print(".");
  }
  Serial.println("wifi config ok");
}
/**
* 加载存储的信息，并检查是否进行了反复5次重启恢复出厂信息
*/
uint8_t* p = (uint8_t*)(&config);
void loadConfig() {
  uint8_t mac[6];
  WiFi.macAddress(mac);
  EEPROM.begin(256);
  for (int i = 0; i < sizeof(config); i++) {
    *(p + i) = EEPROM.read(i);
  }
  config.reboot = config.reboot + 1;
  if (config.reboot >= 4) {
    restoreFactory();
  }
  if (config.magic != 0xAA) {
    config_flag = 1;
  }
  EEPROM.begin(256);
  for (int i = 0; i < sizeof(config); i++) {
    EEPROM.write(i, *(p + i));
  }
  EEPROM.commit();
  delay(2000);
  EEPROM.begin(256);
  config.reboot = 0;
  for (int i = 0; i < sizeof(config); i++) {
    EEPROM.write(i, *(p + i));
  }
  EEPROM.commit();
  delay(2000);
}
/**
* 恢复出厂设置，清除存储的wifi信息
*/
void restoreFactory() {
  Serial.println("Restore Factory....... ");
  config.magic = 0x00;
  strcpy(config.stassid, "");
  strcpy(config.stapsw, "");
  strcpy(config.cuid, "");
  strcpy(config.ctopic, "");
  config.magic = 0x00;
  saveConfig();
  delayRestart(1);
  while (1) {
    delay(100);
  }
}
/**
* 检查是否需要airkiss配网
*/
void waitKey() {
  if (config_flag == 1) {
    doSmartconfig();
  }
}

void setup() {
  Serial.begin(115200);
  WOL.setRepeat(3, 100);
  pinMode(buttonPin, INPUT_PULLUP);                                        // 设置led引脚为输入引脚
  attachInterrupt(digitalPinToInterrupt(buttonPin), checkSwitch, RISING);  //设置中断
  pinMode(LED_Pin, OUTPUT);
  digitalWrite(LED_Pin, ledState);  //写入默认状态
  pinMode(LedBlink, OUTPUT);
  digitalWrite(LedBlink, LOW);  //指示灯引脚

  Serial.println("Beginning...");

  topicMac = WiFi.macAddress().substring(8);  //取mac地址做主题用
  topicMac.replace(":", "");                  //去掉:号
  topicMac = topicMac + aptype;
  loadConfig();
  waitKey();
  initWiFi();
  getUid(topicMac, false);
  //按键配置
  ButtonConfig* buttonConfig = ButtonConfig::getSystemButtonConfig();
  buttonConfig->setEventHandler(handleEvent);
  buttonConfig->setFeature(ButtonConfig::kFeatureLongPress);
  buttonConfig->setFeature(ButtonConfig::kFeatureRepeatPress);
  buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterLongPress);
  buttonConfig->setLongPressDelay(5000);  //长按时间5秒

  detachInterrupt(digitalPinToInterrupt(buttonPin));  //删除外部中断
  client.setServer(mqtt_server, mqtt_server_port);
  client.setCallback(callback);
  digitalWrite(LedBlink, LOW);  //指示灯引脚

  WOL.calculateBroadcastAddress(WiFi.localIP(), WiFi.subnetMask());  //wol
  Serial.printf("wake MAC:%s\n",config.MACAddress);
}
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  ledButton.check();  //按键检查
}

//打开灯泡
void turnOnLed() {
  Serial.println("Turn ON");
  digitalWrite(LED_Pin, LOW);
  WOL.sendMagicPacket(config.MACAddress);
}
//关闭灯泡
void turnOffLed() {
  Serial.println("Turn OFF");
  digitalWrite(LED_Pin, HIGH);
}